#pragma once

//#include "stdafx.h"

enum EColliderType{
	COLLIDER_BOX = 0,
	COLLIDER_SPHERE
};

#include "QuadTree.h"

class Collider;
class ColliderListener{
public:
	virtual void RemoveMe(Collider* collider) = 0;
};

class Entity;
class Collider {
public:
	Collider(ColliderListener* listener) : m_listener(listener), m_user_data(nullptr), m_xz_bounding_box(nullptr), m_x(0.0f), m_y(0.0f), m_z(0.0f){}
	virtual ~Collider(void){}
	virtual bool Intersects(Collider*) = 0;
	virtual void Update(const Vector3&) = 0;
	const EColliderType GetType() const { return m_type; }
	void SetUserData(Entity* user_data) { m_user_data = user_data; }						// Set the entity pointer for this collider
	Entity* GetUserData() const { return m_user_data; }
	void Destroy() { m_listener->RemoveMe(this); }
	void SetXZBoundingBox(XZBoundingBox* bounding_box) { m_xz_bounding_box = bounding_box; }
	XZBoundingBox* GetXZBoundingBox() { return m_xz_bounding_box; }
	float GetX() const { return m_x; }
	float GetY() const { return m_y; }
	float GetZ() const { return m_z; }
protected:
	EColliderType m_type;
	Entity* m_user_data;
	ColliderListener* m_listener;
	XZBoundingBox* m_xz_bounding_box;		//For QuadTree
	float m_x, m_y, m_z;
};

class SphereCollider : public Collider {
public:
	SphereCollider(ColliderListener* listener, float p_radius) : Collider(listener) { m_bounding_sphere.Radius = p_radius; m_type = COLLIDER_SPHERE; }
	virtual ~SphereCollider(void){}

	bool Intersects(Collider* collider);
	virtual void Update(const Vector3& p_position){
		m_bounding_sphere.Center.x = p_position.x;
		m_bounding_sphere.Center.y = p_position.y;
		m_bounding_sphere.Center.z = p_position.z;
		m_x = p_position.x;
		m_y = p_position.y;
		m_z = p_position.z;
		if (m_xz_bounding_box){
			m_xz_bounding_box->center.x = p_position.x;
			m_xz_bounding_box->center.z = p_position.z;
		}
	}

	void SetRadius(float p_radius){ m_bounding_sphere.Radius = p_radius; }
	const DirectX::BoundingSphere& GetBoundingSphere() { return m_bounding_sphere; }

protected:
	DirectX::BoundingSphere m_bounding_sphere;
};

class BoxCollider : public Collider {
public:
	BoxCollider(ColliderListener* listener, float x, float y, float z) : Collider(listener){ m_bounding_box.Extents.x = x; m_bounding_box.Extents.y = y; m_bounding_box.Extents.z = z; m_type = COLLIDER_BOX; }
	BoxCollider(ColliderListener* listener, const DirectX::XMFLOAT3& extents) : Collider(listener) { m_bounding_box.Extents = extents; m_type = COLLIDER_BOX; }
	virtual ~BoxCollider(void){}

	bool Intersects(Collider* collider);
	virtual void Update(const Vector3& p_position){
		m_bounding_box.Center.x = p_position.x;
		m_bounding_box.Center.y = p_position.y;
		m_bounding_box.Center.z = p_position.z;
		m_x = p_position.x;
		m_y = p_position.y;
		m_z = p_position.z;
		if (m_xz_bounding_box){
			m_xz_bounding_box->center.x = p_position.x;
			m_xz_bounding_box->center.z = p_position.z;
		}
	}

	void SetExtents(float x, float y, float z){ m_bounding_box.Extents.x = x; m_bounding_box.Extents.y = y; m_bounding_box.Extents.z = z; }
	void SetExtents(const DirectX::XMFLOAT3& extents) { m_bounding_box.Extents = extents; }
	const DirectX::BoundingBox& GetBoundingBox() { return m_bounding_box; }

protected:
	DirectX::BoundingBox m_bounding_box;
};

class Entity;
class ScanCollider : public SphereCollider {
public:
	ScanCollider(ColliderListener* listener, float radius) : SphereCollider(listener, radius) {}
	virtual ~ScanCollider(void){}
	void Update(const Vector3& p_position, Entity* target);

protected:

};